package cn.wmw.xyy.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.wmw.result.JsonResult;
import cn.wmw.xyy.VerifyConstant.VerifyConst;
import cn.wmw.xyy.bo.RedisSmsVerifyBo;
import cn.wmw.xyy.domain.CodeUser;
import cn.wmw.xyy.domain.MessageSms;
import cn.wmw.xyy.properties.VerifyCodeProperties;
import cn.wmw.xyy.service.ICodeUserService;
import cn.wmw.xyy.service.IMessageBannerService;
import cn.wmw.xyy.service.IMessageSmsService;
import cn.wmw.xyy.utils.AssertUtil;
import cn.wmw.utils.StrUtils;
import cn.wmw.utils.VerifyCodeUtils;
import cn.wmw.xyy.dto.SmsCodeDto;
import cn.wmw.xyy.exception.GlobalExceptionEnum;
import cn.wmw.xyy.service.IVerifyCodeService;
import cn.wmw.xyy.utils.QRCodeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;


@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private IMessageSmsService iMessageSmsService;

    @Autowired
    private VerifyCodeProperties verifyCodeProperties;

    @Autowired
    private IMessageBannerService messageBannerService;

    @Autowired
    private ICodeUserService codeUserService;

    
    /**
     * 获取图形验证码
     * @param imageCodeKey
     * @return
     */
    @Override
    public String graph(String imageCodeKey) {
        String code = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(imageCodeKey,code, 5, TimeUnit.MINUTES);
        String base64Str = VerifyCodeUtils.verifyCode(100, 35, code);
        return base64Str;
    }

    /**
     * 获取手机验证码
     * @param dto
     */
    @Override
    public void smsCode(SmsCodeDto dto) {
        String mobile = dto.getMobile();
        String imageCodeKey = dto.getImageCodeKey();
        String imageCode = dto.getImageCode();
        //1.参数校验
        AssertUtil.isPhone(mobile,GlobalExceptionEnum.COMM_PHONE_ERROR);
        //2.图形验证码校验
        String redisImageCode = (String)redisTemplate.opsForValue().get(imageCodeKey);
        AssertUtil.isEqualsIgnoreCase(imageCode,redisImageCode,GlobalExceptionEnum.COMM_VERIFYCODE_ERROR);
        //todo 2.1校验图形验证码是否过期

        //3.拼接业务键+手机号去redis中查询验证码
        String registerKey = String.format(VerifyConst.REDIS_REGISTER_PHONE,mobile);
        Object o =redisTemplate.opsForValue().get(registerKey);
        Date date = new Date();
        String code = "";
        //4.判断短信验证码是否为空
        code = smsCode(o, date);
        RedisSmsVerifyBo redisValue = new RedisSmsVerifyBo(date.getTime(), code);
        Long overTime = verifyCodeProperties.getOverTime();
        redisTemplate.opsForValue().set(registerKey,redisValue,overTime,TimeUnit.MINUTES);
        //5.存短信日志
        long overTimeMin = overTime / verifyCodeProperties.getMillisecondToMinute();
        String context =String.format(verifyCodeProperties.getContent(),code,overTimeMin);
        saveMessage(date, context);
        //6.发送短信验证码
        log.info(context);
        //此处为调用发送短信验证码工具类
        // SmsUtil.sendSms(mobile,context);
    }

    @Override
    public String getLinkCode() {
        CodeUser codeUser = codeUserService.selectByUserId(7L);
        if(codeUser != null){
            return codeUser.getCode();
        }
        // 获取四位随机数
        String complexRandomString = StrUtils.getComplexRandomString(verifyCodeProperties.getLinkCodeSize());
        // 将用户id和该4位验证码存入数据库中
        CodeUser codeUser1 = new CodeUser();
        codeUser1.setUserId(1L);
        codeUser1.setCode(complexRandomString);
        codeUserService.insert(codeUser1);
        return complexRandomString;
    }

    @Override
    public JsonResult QRCode(String code) {
        // 获取完整的专属链接
        String link = verifyCodeProperties.getExclusiveLink() + code;

        BufferedImage image = QrCodeUtil.generate(link, 200, 200);
        //输出流
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        try {
            ImageIO.write(image, "png", stream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String base64 = Base64.encode(stream.toByteArray());
        return JsonResult.success(base64);
    }

    private void saveMessage(Date date, String context) {
        MessageSms messageSms = new MessageSms();
        messageSms.setTitle(verifyCodeProperties.getTitle());
        messageSms.setContent(context);
        String ip = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest().getRemoteAddr();
        messageSms.setIp(ip);
        messageSms.setSendTime(date);
        iMessageSmsService.insert(messageSms);
    }

    private String smsCode(Object o, Date date) {
        String code;
        if (null == o){
            //4.1 判断结果为空，过期或者没有发送，生成一个新的验证码
            code = StrUtils.getComplexRandomString(4);
        }else {
            //4.2 判断结果不为空，将旧的验证码取出来,判断发送时长间隔是否大于一分钟
            RedisSmsVerifyBo redisValue = (RedisSmsVerifyBo)o;
            // todo 此处有误
            boolean interval = date.getTime() - redisValue.getDate() >= verifyCodeProperties.getIntervalTime();//大于返回true,小于返回false
            AssertUtil.isTrue(interval,GlobalExceptionEnum.COMM_VERIFYCODE_REPEAT_ERROR);
            code =redisValue.getCode();
        }
        return code;
    }
}
